﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace EscapeFromLenovo
{
    /// <summary>
    /// Dr. Bill's video game alter ego
    /// </summary>
    class Player 
    {
        //BASIC MEMBER VARIABLES
        Texture2D textureImage;
        public Vector2 position;
        protected Point frameSize;
        int collisionOffset;//to make the collisions more realistic
        Point currentFrame;
        Point sheetSize;
        int timeSinceLastFrame = 0;
        int millisecondsPerFrame;
        protected Vector2 speed;
        const int defaultMillisecondsPerFrame = 130;
        const int BILL_SPEED = 6;       
        enum State { Walking, Jumping }
        State currentState = State.Walking;
        Vector2 startingPosition = Vector2.Zero;
        Vector2 direction = Vector2.Zero;
        KeyboardState prevKeyboardState;

        
        //CONSTRUCTOR ONE: provides a default millisecondsPerFrame
        public Player(Texture2D textureImage, Vector2 position, Point frameSize, int collisionOffset, Point currentFrame, Point sheetSize) :
            this(textureImage, position, frameSize, collisionOffset, currentFrame, sheetSize, defaultMillisecondsPerFrame)
        { }

        //CONSTRUCTOR TWO: requires a millisecondsPerFrame argument
        public Player(Texture2D textureImage, Vector2 position, Point frameSize, int collisionOffset, Point currentFrame, Point sheetSize, int millisecondsPerFrame)
        {
            this.textureImage = textureImage;
            this.position = position;
            this.frameSize = frameSize;
            this.collisionOffset = collisionOffset;
            this.currentFrame = currentFrame;
            this.sheetSize = sheetSize;
            this.millisecondsPerFrame = millisecondsPerFrame;
        }

        //COLLSION RECTANGLE: the "Bounding-Box" which surrounds and follows the player, and can be intersected by other objects
        public Rectangle collisionRect
        {
            get
            {
                return new Rectangle((int)position.X + collisionOffset,
                                     (int)position.Y + collisionOffset,
                                     frameSize.X - (collisionOffset * 2),
                                     frameSize.Y - (collisionOffset * 2));
            }
        }
        
        //UPDATE METHOD
        public void Update(GameTime gameTime, Rectangle clientBounds)
        {
            //Gets current state of keyboard, passes it to two methods, UpdateMovement and UpdateJump
            KeyboardState currentKeyboardState = Keyboard.GetState();
            UpdateMovement(currentKeyboardState, gameTime);
            UpdateJump(currentKeyboardState, gameTime);
            //Sets previous keyboard state to current keyboard state
            prevKeyboardState = currentKeyboardState;
            //Using the values set by UpdateMovement and UpdateJump, the position of the player is altered
            position += direction * speed;

            //WINDOW BOUNDS: to keep player in
            if(position.X < 0)
                position.X = 0;
            if(position.Y < 0)
                position.Y = 0;
            if(position.X > clientBounds.Width - frameSize.X)
                position.X = clientBounds.Width - frameSize.X;
            if(position.Y > clientBounds.Height - frameSize.Y)
                position.Y = clientBounds.Height - frameSize.Y;
        }

        //UPDATE MOVEMENT: for left and right walking
        public void UpdateMovement(KeyboardState currentKeyboardState, GameTime gameTime)
        {
            //GAMEPAD STATE: for the Xbox 360 controller
            GamePadState gamepadState = GamePad.GetState(PlayerIndex.One);

            if (currentState == State.Walking)
            {
                direction = Vector2.Zero;
                speed = Vector2.Zero;
                //KEYBOARD and GAMEPAD MOVE: WALK LEFT
                if (currentKeyboardState.IsKeyDown(Keys.Left) == true || gamepadState.ThumbSticks.Left.X < 0 == true)
                {
                    //Animation
                    timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
                    if (timeSinceLastFrame > millisecondsPerFrame)
                    {
                        timeSinceLastFrame -= millisecondsPerFrame;
                        ++currentFrame.X;
                        currentFrame.Y = 1;
                        if (currentFrame.X >= sheetSize.X)
                        {
                            currentFrame.X = 0;
                        }
                    }
                    //Set direction and speed, which will be used by the Update method to change the position
                    direction.X = -1;
                    speed.X = BILL_SPEED;
                }

                //KEYBOARD and GAMEPAD: WALK RIGHT
                else if (currentKeyboardState.IsKeyDown(Keys.Right) == true || gamepadState.ThumbSticks.Left.X > 0 == true)
                {
                    //Animation
                    timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
                    if (timeSinceLastFrame > millisecondsPerFrame)
                    {
                        timeSinceLastFrame -= millisecondsPerFrame;
                        ++currentFrame.X;
                        currentFrame.Y = 0;
                        if (currentFrame.X >= sheetSize.X)
                        {
                            currentFrame.X = 0;
                        }
                    }
                    //Set direction and speed
                    direction.X = 1;
                    speed.X = BILL_SPEED;
                }                   
            }
        }

        //UPDATE JUMP: for avoiding obstacles
        public void UpdateJump(KeyboardState currentKeyboardState, GameTime gameTime)
        {
            //GAMEPAD STATE
            GamePadState gamepadState = GamePad.GetState(PlayerIndex.One);

            if (currentState == State.Walking)
            {
                if (currentKeyboardState.IsKeyDown(Keys.Space) == true && prevKeyboardState.IsKeyDown(Keys.Space) == false || gamepadState.IsButtonDown(Buttons.A) == true)
                {
                    //If the spacebar or "A" button has been pressed, call Jump function
                    Jump(gameTime);
                }
            }

            else if (currentState == State.Jumping)
            {
                if (startingPosition.Y - position.Y > 150)
                {
                    //When the apex of the jump has been reached, begin descent
                    direction.Y = 1;
                }
                
                if (position.Y > startingPosition.Y)
                {
                    //Set player back to walking on ground, jump has been completed
                    position.Y = startingPosition.Y;
                    currentState = State.Walking;
                    direction = Vector2.Zero;
                    speed = Vector2.Zero;
                }
            }
        }

        //JUMP FUNCTION
        public void Jump(GameTime gameTime)
        {
            if (currentState != State.Jumping)
            {
                currentState = State.Jumping;
                startingPosition = position;
                //Begin ascent
                direction.Y = -1;
                speed = new Vector2(BILL_SPEED, BILL_SPEED);
            }
                
        }

        //DRAW METHOD: sketches the player on the screen
        public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(textureImage, position, new Rectangle(currentFrame.X * frameSize.X,
                                                                   currentFrame.Y * frameSize.Y,
                                                                   frameSize.X, frameSize.Y), Color.White, 0, Vector2.Zero, 1f, SpriteEffects.None, 0);
        }
    }
}
